<template>
    <Mapbox :mapOnLoadCB="mapOnLoadCB"></Mapbox>
    <div class='map-overlay'>
        <fieldset>
            <input id='feature-filter' type='text' placeholder='Filter results by name'/>
        </fieldset>
        <div id='feature-listing' class='listing'></div>
    </div>
</template>

<script>
import {ref} from "vue"
import Mapbox from "@/components/common/Mapbox.component.vue"
import MapboxCommonService from "@/service/map/MapboxCommonService"

export default {
    name: "SwitchFilter.component",
    components: {Mapbox},
    setup() {

        let mapStore = ref({});
        let mapOnLoadCB = (map) => {
            mapStore.value = map;
            MapboxCommonService.setCZBP(map, [-98, 38.88], 3)
            map.setMinZoom(1)
            map.setMaxZoom(5)

            // 在 map view 中筛选要素，移动地图以查询矢量切片图层中的可视要素，并通过输入文本筛选要素。
            // Holds visible airport features for filtering
            let airports = [];

            // Create a popup, but don't add it to the map yet.
            let popup = new mapboxgl.Popup({
                closeButton: false
            });

            let filterEl = document.getElementById('feature-filter');
            let listingEl = document.getElementById('feature-listing');

            const renderListings = (features) => {
                // Clear any existing listings
                listingEl.innerHTML = '';
                if (features.length) {
                    features.forEach((feature) => {
                        let prop = feature.properties;
                        let item = document.createElement('a');
                        item.href = prop.wikipedia;
                        item.target = '_blank';
                        item.textContent = prop.name + ' (' + prop.abbrev + ')';
                        item.addEventListener('mouseover', () => {
                            // Highlight corresponding feature on the map
                            popup.setLngLat(feature.geometry.coordinates)
                                .setText(feature.properties.name + ' (' + feature.properties.abbrev + ')')
                                .addTo(map);
                        });
                        listingEl.appendChild(item);
                    });

                    // Show the filter input
                    filterEl.parentNode.style.display = 'block';
                } else {
                    let empty = document.createElement('p');
                    empty.textContent = 'Drag the map to populate results';
                    listingEl.appendChild(empty);

                    // Hide the filter input
                    filterEl.parentNode.style.display = 'none';

                    // remove features filter
                    map.setFilter('airport', ['has', 'abbrev']);
                }
            }

            const normalize = (string) => {
                return string.trim().toLowerCase();
            }

            const getUniqueFeatures = (array, comparatorProperty) => {
                let existingFeatureKeys = {};
                // Because features come from tiled vector data, feature geometries may be split
                // or duplicated across tile boundaries and, as a result, features may appear
                // multiple times in query results.
                return array.filter((el) => {
                    if (existingFeatureKeys[el.properties[comparatorProperty]]) {
                        return false;
                    } else {
                        existingFeatureKeys[el.properties[comparatorProperty]] = true;
                        return true;
                    }
                });
            }
            map.addLayer({
                "id": "airport",
                "source": {
                    "type": "vector",
                    "url": `${window.location.origin}/mapbox/libs/mapbox/assets/mapbox.04w69w5j.json`
                },
                "source-layer": "ne_10m_airports",
                "type": "symbol",
                "layout": {
                    "icon-image": "airport-15",
                    "icon-padding": 0,
                    "icon-allow-overlap": true
                }
            });

            map.on('moveend', () => {
                let features = map.queryRenderedFeatures({layers: ['airport']});

                if (features) {
                    let uniqueFeatures = getUniqueFeatures(features, "iata_code");
                    // Populate features for the listing overlay.
                    renderListings(uniqueFeatures);

                    // Clear the input container
                    filterEl.value = '';

                    // Store the current features in sn `airports` letiable to
                    // later use for filtering on `keyup`.
                    airports = uniqueFeatures;
                }
            });

            map.on('mousemove', 'airport', (e) => {
                // Change the cursor style as a UI indicator.
                map.getCanvas().style.cursor = 'pointer';

                // Populate the popup and set its coordinates based on the feature.
                let feature = e.features[0];
                popup.setLngLat(feature.geometry.coordinates)
                    .setText(feature.properties.name + ' (' + feature.properties.abbrev + ')')
                    .addTo(map);
            });

            map.on('mouseleave', 'airport', () => {
                map.getCanvas().style.cursor = '';
                popup.remove();
            });

            filterEl.addEventListener('keyup', (e) => {
                let value = normalize(e.target.value);

                // Filter visible features that don't match the input value.
                let filtered = airports.filter((feature) => {
                    let name = normalize(feature.properties.name);
                    let code = normalize(feature.properties.abbrev);
                    return name.indexOf(value) > -1 || code.indexOf(value) > -1;
                });

                // Populate the sidebar with filtered results
                renderListings(filtered);

                // Set the filter to populate features into the layer.
                map.setFilter('airport', ['match', ['get', 'abbrev'], filtered.map((feature) => {
                    return feature.properties.abbrev;
                }), true, false]);
            });

            // Call this function on initialization
            // passing an empty array to render an empty state
            renderListings([]);
        };

        return {
            mapOnLoadCB
        }
    }
}
</script>

<style scoped lang="scss">
.map-overlay {
    position: absolute;
    width: 20%;
    top: 0;
    bottom: 0;
    left: 0;
    font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
    background-color: #fff;
    max-height: 100%;
    overflow: hidden;
    fieldset {
        display: none;
        background: #ddd;
        border: none;
        padding: 10px;
        margin: 0;
    }
    input {
        display: block;
        border: none;
        width: 100%;
        border-radius: 3px;
        padding: 10px;
        margin: 0;
    }
    .listing {
        overflow: auto;
        max-height: 100%;
        & > * {
            display: block;
            padding: 5px 10px;
            margin: 0;
        }
        a {
            border-bottom: 1px solid rgba(0, 0, 0, 0.1);
            color: #404;
            text-decoration: none;
        }
        &:last-child {
            border: none;
        }
        &:hover {
            background: #f0f0f0;
        }
    }
}
</style>
